package com.jtny.nytb.equipment.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jtny.component.entity.LocalHolder;
import com.jtny.component.exception.ServiceException;
import com.jtny.component.redis.core.RedisValueService;
import com.jtny.component.util.BeanUtils;
import com.jtny.nytb.equipment.dao.dataalgorithm.DataAlgorithmDAO;
import com.jtny.nytb.equipment.dao.dataalgorithm.DataAlgorithmFormulaConfigDAO;
import com.jtny.nytb.equipment.dao.dataalgorithm.DataAlgorithmParamConfigDAO;
import com.jtny.nytb.equipment.dao.dataalgorithm.DataAlgorithmScriptConfigDAO;
import com.jtny.nytb.equipment.domain.dataalgorithm.DataAlgorithmDO;
import com.jtny.nytb.equipment.domain.dataalgorithm.DataAlgorithmFormulaConfigDO;
import com.jtny.nytb.equipment.domain.dataalgorithm.DataAlgorithmParamConfigDO;
import com.jtny.nytb.equipment.domain.dataalgorithm.DataAlgorithmScriptConfigDO;
import com.jtny.nytb.config.datafactor.enums.DataParamChartEnum;
import com.jtny.nytb.config.datafactor.enums.DataParamFrequencyUnitEnum;
import com.jtny.nytb.config.datafactor.enums.DataParamSourceEnum;
import com.jtny.nytb.config.datafactor.enums.DataParamTypeEnum;
import com.jtny.nytb.config.dictionary.dto.DictionaryDataDTO;
import com.jtny.nytb.config.dictionary.service.DictionaryBiz;

import com.jtny.nytb.equipment.dto.dataalgorithm.*;
import com.jtny.nytb.equipment.dto.dataparam.*;
import com.jtny.nytb.equipment.dto.device.DataParamCoreDTO;
import com.jtny.nytb.equipment.dto.excel.*;
import com.jtny.nytb.equipment.dto.model.ExcelModelDTO;
import com.jtny.nytb.equipment.dto.model.ModelInfoDTO;
import com.jtny.nytb.equipment.dto.rule.CodeRuleDictDTO;
import com.jtny.nytb.equipment.enums.DataAlgorithmTypeEnum;
import com.jtny.nytb.equipment.enums.DataParamImportEnum;
import com.jtny.nytb.equipment.enums.ExcelCodeRuleEnum;
import com.jtny.nytb.equipment.errorcode.DataAlgorithmErrorCodeEnum;
import com.jtny.nytb.equipment.service.CodeRuleService;
import com.jtny.nytb.equipment.service.DataParamTempService;
import com.jtny.nytb.equipment.service.RedisService;

import com.jtny.nytb.equipment.vo.dataparam.AlgorithmExcelVO;
import com.jtny.nytb.equipment.vo.dataparam.DataParamTempVO;
import com.jtny.nytb.equipment.vo.excel.*;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author 智慧能源中心 - 伍天宇
 * @package com.jtny.nytb.equipment.biz
 * @fileName RedisBizImpl.java
 * @createTime 2023年10月11日 13:37
 * @Copyright© 2023 jtny
 * 江投能源技术研究院 版权所有
 */
@Service
@Slf4j
public class RedisServiceImpl implements RedisService {
    private static final Logger logger = LoggerFactory.getLogger(RedisServiceImpl.class);
    @Resource
    private CodeRuleService codeRuleClient;
    @Resource
    private DataParamTempService dataParamTempClient;


    @Resource
    private DictionaryBiz dictionaryClient;
    @Resource
    private RedisValueService redisValueService;
    public static final String EXCEL_PREFIX = "excel:";
    private final String DICT_RULE_PREFIX = EXCEL_PREFIX + "dictRule_";
    private final String DATA_PARAM_TEMP_PREFIX = EXCEL_PREFIX + "dataParamTemp_";
    private final String DATA_PARAM_IMPORT_PREFIX = EXCEL_PREFIX + "dataParamImport_";
    private final String EQUIPMENT_DATA_PARAM_RELATION_PREFIX = EXCEL_PREFIX + "equipmentDataParamRelation_";
    private final String ALGORITHM_PREFIX = EXCEL_PREFIX + "algorithm_";
    private final String LABEL_PREFIX = EXCEL_PREFIX + "label_";
    private final String DATA_PARAM_PREFIX = EXCEL_PREFIX + "dataParam_";

    /**
     * 按名称获取字典规则
     * 获取规则字典
     *
     * @param type 类型
     * @param name 名字
     * @return {@link CodeRuleDictDTO}
     */
    @Override
    public CodeRuleDictDTO getDictRuleByName(String type, String name) {
        return getRedisByKey(DICT_RULE_PREFIX + name, CodeRuleDictDTO.class);
    }

    /**
     * 按名称获取设备模型id
     *
     * @param name 名字
     * @return {@link DataParamTempDTO}
     */
    @Override
    public DataParamTempDTO getDataParamTempDTOByName(String name) {
        DataParamTempDTO result;
        String string = getRedisByKey(DATA_PARAM_IMPORT_PREFIX + name);
        if (StrUtil.isBlank(string) || "null".equals(string)) {
            result = BeanUtils.copyToObject(dataParamTempClient.getDataParamTempByName(name), DataParamTempDTO.class);
            setRedisByKey(DATA_PARAM_IMPORT_PREFIX + name, JSON.toJSONString(result));
        } else {
            result = JSON.parseObject(string, DataParamTempDTO.class);
        }
        return result;
    }









    @Override
    public void setDataParamBasePref(List<ExcelDataParamVO> dataParamExcelList, DataParamImportEnum typeEnum) {
        List<DataParamTempVO> dataParamList = buildDataParamListPref(dataParamExcelList, typeEnum);
        Map<String, List<DataParamTempVO>> mapEquipmentDataParamList = dataParamList.stream()
                .collect(Collectors.groupingBy(DataParamTempVO::getEquipmentName, Collectors.toList()));
        mapEquipmentDataParamList.forEach(this::setAllRedisDataParamTemp);
    }

    public static final String DATA_PARAM_IMPORT = EXCEL_PREFIX + "dataParamTempDTOImport_";

    private void setAllRedisDataParamTemp(String key, List<DataParamTempVO> dataParamTempVOList) {
        List<DataParamTempDTO> collect = dataParamTempVOList.stream().map(DataParamTempVO::buildDTO2).collect(Collectors.toList());
        collect.forEach(this::setDataParamDTO);
        List<String> dataParamNameList = collect.stream().map(DataParamTempDTO::getName).collect(Collectors.toList());
        pushListRedisByKey(DATA_PARAM_IMPORT + key, dataParamNameList);
    }

    private void setDataParamDTO(DataParamTempDTO dataParamTempDTO) {
        setRedisByKey(DATA_PARAM_IMPORT_PREFIX + dataParamTempDTO.getName(), JSON.toJSONString(dataParamTempDTO));
    }

    private DataParamTempDTO getDataParamDTO(String dataParamName) {
        return getRedisByKey(DATA_PARAM_IMPORT_PREFIX + dataParamName, DataParamTempDTO.class);
    }


    private List<DataParamTempDTO> listAllDataParamTempByEquipmentName(String equipmentName) {
        List<String> dataParamNameList = listRedisByKey(DATA_PARAM_IMPORT + equipmentName, String.class);
        assert dataParamNameList != null;
        return dataParamNameList.stream().map(this::getDataParamDTO).collect(Collectors.toList());
    }

    private DataParamTempDTO dataParamTempByDataParamName(String paramName){
        return getRedisByKey(DATA_PARAM_IMPORT_PREFIX + paramName, DataParamTempDTO.class);
    }

    private AlgorithmTempDTO algorithmTempByDataParamName(String paramName){
        return getRedisByKey(DATA_PARAM_IMPORT_PREFIX + paramName, AlgorithmTempDTO.class);
    }

    private LabelTempDTO labelTempDTOByDataParamName(String paramName){
        return getRedisByKey(DATA_PARAM_IMPORT_PREFIX + paramName, LabelTempDTO.class);
    }

    @Override
    public void setFrequencyExcel(List<ExcelFrequencyVO> frequencyExcelList) {
        frequencyExcelList.forEach(vo -> {
            DataParamTempDTO dataParamDTO = getDataParamDTO(vo.getDataParamName());
            if (ObjectUtil.isNotEmpty(dataParamDTO)) {
                dataParamDTO.setFrequency(vo.getFrequency());
                dataParamDTO.setFrequencyUnit(DataParamFrequencyUnitEnum.getUnitByName(vo.getFrequencyUnit()));
                setDataParamDTO(dataParamDTO);
            }
        });
    }

    @Override
    public void setAlgorithmExcel(List<AlgorithmExcelVO> algorithmExcelList) {
        List<String> algorithmNameList = algorithmExcelList.stream()
                .map(AlgorithmExcelVO::getAlgorithmName).distinct().collect(Collectors.toList());
        Map<String, DataAlgorithmScriptAndFormulaDTO> map = mapAlgorithmByNameList(algorithmNameList);
        algorithmExcelList.forEach(vo -> {
            DataParamTempDTO dataParamDTO = getDataParamDTO(vo.getDataParamName());
            if (ObjectUtil.isEmpty(dataParamDTO)) {
                DataParamTempDTO dataParamTempDTO = new DataParamTempDTO();
                DataAlgorithmScriptAndFormulaDTO algorithm = map.get(vo.getAlgorithmName());
                if (ObjectUtil.isNotEmpty(algorithm)) {
                    // 保存频率
                    dataParamTempDTO.setFrequency(vo.getFrequency());
                    dataParamTempDTO.setFrequencyUnit(DataParamFrequencyUnitEnum.getUnitByName(vo.getFrequencyUnit()));
                    // 保存算法
                    dataParamTempDTO.setAlgorithm(buildAlgorithmTempDTO(algorithm));
                    dataParamTempDTO.setName(vo.getDataParamName());
                    setDataParamDTO(dataParamTempDTO);
                }
            }
        });
    }
    private DataAlgorithmDAO dataAlgorithmDAO;
    private DataAlgorithmFormulaConfigDAO algorithmFormulaConfigDAO;
    private DataAlgorithmScriptConfigDAO algorithmScriptConfigDAO;
    private DataAlgorithmParamConfigDAO algorithmParamConfigDAO;
    public Map<String, DataAlgorithmScriptAndFormulaDTO> mapAlgorithmByNameList(List<String> nameList) {
        List<DataAlgorithmDO> dataAlgorithmDOList = dataAlgorithmDAO.selectList(new LambdaQueryWrapper<DataAlgorithmDO>()
                .in(DataAlgorithmDO::getName, nameList));
        if (CollectionUtil.isNotEmpty(dataAlgorithmDOList)) {
            Map<String, DataAlgorithmScriptAndFormulaDTO> map = new HashMap<>();
            for (DataAlgorithmDO dataAlgorithmDO : dataAlgorithmDOList) {
                map.put(dataAlgorithmDO.getName(), getFormulaOrScriptById(dataAlgorithmDO.getId()));
            }
            return map;
        }
        return new HashMap<>();
    }
    public DataAlgorithmScriptAndFormulaDTO getFormulaOrScriptById(Long algorithmId) {
        DataAlgorithmScriptAndFormulaDTO scriptAndFormulaDTO = new DataAlgorithmScriptAndFormulaDTO();
        //根据算法id查询算法基本信息
        DataAlgorithmDO dataAlgorithmDO = dataAlgorithmDAO.selectById(algorithmId);

        if (ObjectUtil.isNull(dataAlgorithmDO)) {
            throw new ServiceException(DataAlgorithmErrorCodeEnum.PARAM_NOT_FIND.getErrorCode(), DataAlgorithmErrorCodeEnum.PARAM_NOT_FIND.getErrorMessage());
        }
        //算法基本信息DO对象转为DTO对象
        DataAlgorithmDTO dataAlgorithmDTO = BeanUtils.copyToObject(dataAlgorithmDO, DataAlgorithmDTO.class);
        scriptAndFormulaDTO.setDataAlgorithmDTO(dataAlgorithmDTO);

        //当算法配置方案为计算公式配置
        if (dataAlgorithmDO.getConfigurationScheme().equals("计算公式配置")) {
            List<DataAlgorithmParamConfigDTO> paramConfigDTOS = new ArrayList<>();
            DataAlgorithmFormulaConfigDTO formulaConfigDTO = new DataAlgorithmFormulaConfigDTO();
            //获取计算参数配置信息
            List<DataAlgorithmParamConfigDO> paramConfigDOList = algorithmParamConfigDAO.findParamConfigByAlgorithmId(algorithmId);
            if (CollectionUtil.isEmpty(paramConfigDOList)) {
                paramConfigDTOS = new ArrayList<>();
            } else {
                paramConfigDTOS = BeanUtils.copyToList(paramConfigDOList, DataAlgorithmParamConfigDTO.class);
            }

            //获取计算公式
            List<DataAlgorithmFormulaConfigDO> formulaConfigDOList = algorithmFormulaConfigDAO.findFormulaConfigByAlgorithmId(algorithmId);
            if (CollectionUtil.isEmpty(formulaConfigDOList)) {
                formulaConfigDTO = new DataAlgorithmFormulaConfigDTO();
            } else {
                DataAlgorithmFormulaConfigDO formulaConfig = formulaConfigDOList.get(0);
                formulaConfigDTO = BeanUtils.copyToObject(formulaConfig, DataAlgorithmFormulaConfigDTO.class);
            }
            //赋值
            formulaConfigDTO.setAlgorithmId(algorithmId);
            formulaConfigDTO.setParamConfigDTOList(paramConfigDTOS);

            scriptAndFormulaDTO.setDataAlgorithmFormulaConfigDTO(formulaConfigDTO);
        }
        //当算法配置方案为算法脚本配置
        if (dataAlgorithmDO.getConfigurationScheme().equals("算法脚本配置")) {
            List<DataAlgorithmParamConfigDTO> paramConfigDOS = new ArrayList<>();
            DataAlgorithmScriptConfigDTO scriptConfigDTO = new DataAlgorithmScriptConfigDTO();
            //获取计算参数配置信息
            List<DataAlgorithmParamConfigDO> paramConfigDOList = algorithmParamConfigDAO.findParamConfigInfoById(algorithmId);
            if (CollectionUtil.isEmpty(paramConfigDOList)) {
                paramConfigDOS = new ArrayList<>();
            } else {
                paramConfigDOS = BeanUtils.copyToList(paramConfigDOList, DataAlgorithmParamConfigDTO.class);
            }

            //获取计算公式
            List<DataAlgorithmScriptConfigDO> scriptList = algorithmScriptConfigDAO.findScriptConfigInfoByAlgorithmId(algorithmId);
            if (CollectionUtil.isEmpty(scriptList)) {
                scriptConfigDTO = new DataAlgorithmScriptConfigDTO();
            } else {
                DataAlgorithmScriptConfigDO scriptConfigDO = algorithmScriptConfigDAO.findScriptConfigInfoByAlgorithmId(algorithmId).get(0);
                scriptConfigDTO = BeanUtils.copyToObject(scriptConfigDO, DataAlgorithmScriptConfigDTO.class);
            }
            //赋值
            scriptConfigDTO.setAlgorithmId(algorithmId);
            scriptConfigDTO.setParamConfigDTOList(paramConfigDOS);

            scriptAndFormulaDTO.setDataAlgorithmScriptConfigDTO(scriptConfigDTO);
        }
        return scriptAndFormulaDTO;
    }

    @Override
    public void setAlgorithmParamExcel(List<ExcelAlgorithmParamVO> algorithmParamExcelList) {
//        Map<String, List<ExcelAlgorithmParamVO>> map = algorithmParamExcelList.stream()
//                .collect(Collectors.groupingBy(ExcelAlgorithmParamVO::getDataParamName));
//        map.forEach((dataParamName, voList) -> {
//            DataParamTempDTO dataParamDTO = getDataParamDTO(dataParamName);
//            if (ObjectUtil.isNotEmpty(dataParamDTO)) {
//                AlgorithmTempDTO algorithm = dataParamDTO.getAlgorithm();
//                // 保存算法参数
//                algorithm.setParamTempList(buildAlgorithmParamList(algorithm, voList));
//            }
//        });
    }



    @Override
    public void setAlarmExcel(List<ExcelAlarmVO> alarmExcelList) {
        Map<String, List<AlarmTempDTO>> map = buildAlarmExcelDTOList(alarmExcelList);
        map.forEach((dataParamName, voList) -> {
            DataParamTempDTO dataParamDTO = getDataParamDTO(dataParamName);
            if (ObjectUtil.isNotEmpty(dataParamDTO)) {
                // 保存报警
                dataParamDTO.setAlarmList(voList);
                setDataParamDTO(dataParamDTO);
            }
        });
    }

    /**
     * 获取设备参量关系
     *
     * @param equipmentId 设备ID
     * @return
     */
    @Override
    public DataParamCoreDTO getEquipmentDataParamRelation(Long equipmentId) {
        String dataParamStr = getRedisByKey(EQUIPMENT_DATA_PARAM_RELATION_PREFIX + equipmentId);
        return JSON.parseObject(dataParamStr, DataParamCoreDTO.class);
    }

    /**
     * 删除 Redis 全部清理
     */
    @Override
    public void deleteRedisCleanAll() {
        redisValueService.deleteLike(EXCEL_PREFIX);
    }

    public static final String DICT_ALARM_TYPE = "报警点分类";
    public static final String DICT_ALARM_LEVEL = "报警等级";

    public static final String DICT_EQUIPMENT_PURPOSE = "设备用途";

    private Map<String, String> mapDict(String name) {
        List<DictionaryDataDTO> dictionaryDataDTOS = dictionaryClient.listDictionaryByName(name);
        return dictionaryDataDTOS.stream().collect(Collectors.toMap(DictionaryDataDTO::getDescription, DictionaryDataDTO::getValue));
    }

    /**
     * 获取 报警点分类 字典
     *
     * @return
     */
    @Override
    public Map<String, String> getDictAlarmType() {
        return mapDict(DICT_ALARM_TYPE);
    }

    /**
     * 获取 报警等级 字典
     *
     * @return
     */
    @Override
    public Map<String, String> getDictAlarmLevel() {
        return mapDict(DICT_ALARM_LEVEL);
    }

    /**
     * 按名称设置所有规则字典
     * 按名称 临时设置所有规则字典
     *
     * @param dictNameLists dict 名称列表 名字为拼接格式的
     * @param type          类型
     */
    @Override
    public void setAllRuleDictByName(DataParamImportEnum type, List<String>... dictNameLists) {
        ArrayList<String> tempList = CollUtil.newArrayList();
        for (List<String> dictNameList : dictNameLists) {
            tempList.addAll(dictNameList);
        }
        Map<String, CodeRuleDictDTO> tempMap = codeRuleClient.mapDictRuleByName(type.getCodeRuleTypeEnum().getType(), tempList);
        tempMap.forEach((key, value) -> setRedisByKey(DICT_RULE_PREFIX + key, JSON.toJSONString(value)));
    }

    public static final String RULE_NAME_PREFIX = " " + StrUtil.C_SLASH + " ";

    private String buildEquipmentCodeRule(CodeRuleDictDTO codeRuleDict) {
        return String.format("%d%s", codeRuleDict.getId(), StrUtil.C_COMMA);
    }

    private String buildRuleName(CodeRuleDictDTO codeRuleDict) {
        return codeRuleDict.getDescription() + RULE_NAME_PREFIX;
    }

    private String buildRuleTableData(ExcelCodeRuleEnum excelCodeRuleEnum, CodeRuleDictDTO codeRuleDict) {
        return StrUtil.HTML_QUOTE +
                excelCodeRuleEnum.getName() +
                StrUtil.HTML_QUOTE + StrUtil.COLON + StrUtil.HTML_QUOTE +
                codeRuleDict.getDescription() +
                StrUtil.HTML_QUOTE + StrUtil.COMMA;
    }


    /**
     * 构建规则
     * 构建导入设备的编号生成规则
     *
     * @param enumType      枚举类型
     * @param vo            VO
     * @param dto           DTO
     * @param logRecordName 日志记录名称
     * @return {@link ExcelResultVO}
     */
    @Override
    public Boolean buildRule(DataParamImportEnum enumType,
                             ExcelNormalCodeRuleVO vo,
                             ExcelNormalCodeRuleDTO dto,
                             String logRecordName) {
        ExcelResultVO result = new ExcelResultVO();
        String codeRuleType = enumType.getCodeRuleTypeEnum().getType();
        String equipmentCodeRule = "";
        String ruleName = "";
        // "{"
        String ruleTableData = StrUtil.DELIM_START;
        String energyClassification = vo.getEnergyClassification();
        // 填写了能源分类
        if (StrUtil.isNotBlank(energyClassification)) {
            // 能源分类
            ExcelCodeRuleEnum classificationEnum = ExcelCodeRuleEnum.ENERGY_CLASSIFICATION;
            CodeRuleDictDTO energy = getDictRuleByName(codeRuleType,
                    classificationEnum.getNameSuffix() +
                            vo.getEnergyClassification().trim());
            if (ObjectUtil.isEmpty(energy)) {
                // 能源分类不存在, 记录错误
                setCodeRuleMessage(logRecordName, classificationEnum);
                return Boolean.FALSE;
            } else {
                // 能源分类存在, 设置能源分类id
                dto.setEnergyClassificationId(energy.getId());
                dto.setEnergyClassification(energy.getDescription());
                equipmentCodeRule += buildEquipmentCodeRule(energy);
                ruleName += buildRuleName(energy);
                ruleTableData += buildRuleTableData(classificationEnum, energy);
            }
        }

        String typeStr = vo.getType();
        if (StrUtil.isNotBlank(typeStr)) {
            // 设备类型
            ExcelCodeRuleEnum typeEnum = ExcelCodeRuleEnum.TYPE;
            CodeRuleDictDTO type = getDictRuleByName(codeRuleType,
                    typeEnum.getNameSuffix() +
                            vo.getType().trim());
            if (ObjectUtil.isEmpty(type)) {
                // 设备类型不存在, 记录错误
                setCodeRuleMessage(logRecordName, typeEnum);
                return Boolean.FALSE;
            } else {
                dto.setTypeId(type.getId());
                dto.setType(type.getDescription());
                equipmentCodeRule += buildEquipmentCodeRule(type);
                ruleName += buildRuleName(type);
                ruleTableData += buildRuleTableData(typeEnum, type);
            }
        }

        String brandStr = vo.getBrand();
        if (StrUtil.isNotBlank(brandStr)) {
            // 设备品牌
            ExcelCodeRuleEnum brandEnum = ExcelCodeRuleEnum.BRAND;
            CodeRuleDictDTO brand = getDictRuleByName(codeRuleType, brandEnum.getNameSuffix() + vo.getBrand());
            if (ObjectUtil.isEmpty(brand)) {
                // 设备品牌不存在, 记录错误
                result.setCodeRuleMessage(logRecordName, brandEnum);
                return Boolean.FALSE;
            } else {
                dto.setBrand(brand.getDescription());
                equipmentCodeRule += buildEquipmentCodeRule(brand);
                ruleName += buildRuleName(brand);
                ruleTableData += buildRuleTableData(brandEnum, brand);
            }
        }

        String modelStr = vo.getModel();
        if (StrUtil.isNotBlank(modelStr)) {
            // 设备型号
            ExcelCodeRuleEnum modelEnum = ExcelCodeRuleEnum.MODEL;
            CodeRuleDictDTO model = getDictRuleByName(codeRuleType, modelEnum.getNameSuffix() + vo.getModel());
            if (ObjectUtil.isEmpty(model)) {
                // 设备型号不存在, 记录错误
                setCodeRuleMessage(logRecordName, modelEnum);
                return Boolean.FALSE;
            } else {
                dto.setModel(model.getDescription());
                equipmentCodeRule += buildEquipmentCodeRule(model);
                ruleName += buildRuleName(model);
                ruleTableData += buildRuleTableData(modelEnum, model);
            }
        }

        equipmentCodeRule += "#3";
        dto.setEquipmentCodeRule(equipmentCodeRule);
        ruleName += "3位顺序号";
        dto.setRuleName(ruleName);
        ruleTableData += "\"顺序号/随机码\":\"3位顺序号\"}";
        dto.setRuleTableData(ruleTableData);
//        setSuccessCount();
        return Boolean.TRUE;
    }

    public static final String EXCEL_MODEL_PREFIX = EXCEL_PREFIX + "model_";
    public static final String EXCEL_MODEL_KEY_LIST = EXCEL_PREFIX + "modelKeyList";

    /**
     * 设置所有 Excel 模型
     *
     * @param excelModelList Excel设备DTOS
     */
    @Override
    public void setAllExcelModel(List<ExcelModelDTO> excelModelList) {
        // 获取所有Excel设备名称
        List<String> collect = excelModelList.stream().map(ExcelModelDTO::getName).collect(Collectors.toList());
        pushListRedisByKey(EXCEL_MODEL_KEY_LIST, collect);
        // 设置所有Excel设备
        excelModelList.forEach(this::setExcelModel);
    }

    /**
     * 获取所有要导入的设备
     *
     * @return {@link List}<{@link ExcelEquipmentDTO}>
     */
    @Override
    public List<ExcelModelDTO> listAllExcelModel() {
        List<ExcelModelDTO> result = new ArrayList<>();
        List<String> keyList = listRedisByKey(EXCEL_MODEL_KEY_LIST, String.class);
        if (CollUtil.isNotEmpty(keyList)) {
            keyList.forEach(item -> {
                ExcelModelDTO toImport = getExcelModelDTOByName(item);
                String name = toImport.getName();
                List<ExcelParamDTO> redisKey4ParamList = getRedisKey4ParamList(name);
                toImport.setParamList(redisKey4ParamList);
                result.add(toImport);
            });
        }
        return result;
    }


    /**
     * 获取Excel设备DTOBY名称
     *
     * @param name 名字
     * @return {@link ExcelModelDTO}
     */
    @Override
    public ExcelModelDTO getExcelModelDTOByName(String name) {
        return getRedisByKey(EXCEL_MODEL_PREFIX + name, ExcelModelDTO.class);
    }


    /**
     * 设置 Excel 设备
     *
     * @param excelModel 设备excel
     */
    @Override
    public void setExcelModel(ExcelModelDTO excelModel) {
        setRedis(EXCEL_MODEL_PREFIX + excelModel.getName(), excelModel);
    }

    public static final String EXCEL_EQUIPMENT_PREFIX = EXCEL_PREFIX + "excelEquipment_";
    public static final String EXCEL_EQUIPMENT_KEY_LIST = EXCEL_PREFIX + "excelEquipmentKeyList";

    /**
     * 设置所有Excel设备基础
     *
     * @param equipmentExcelDTOList 设备 excel dtolist
     */
    @Override
    public void setAllExcelEquipmentBase(List<ExcelEquipmentDTO> equipmentExcelDTOList) {
        // 获取所有Excel设备名称
        List<String> collect = equipmentExcelDTOList.stream().map(ExcelEquipmentDTO::getName).collect(Collectors.toList());
        pushListRedisByKey(EXCEL_EQUIPMENT_KEY_LIST, collect);
        // 设置所有Excel设备
        equipmentExcelDTOList.forEach(this::setExcelEquipment);
    }

    /**
     * 获取所有要导入的设备
     *
     * @return {@link List}<{@link ExcelEquipmentDTO}>
     */
    @Override
    public List<ExcelEquipmentDTO> listAllExcelEquipmentBase() {
        List<ExcelEquipmentDTO> result = new ArrayList<>();
        List<String> keyList = listRedisByKey(EXCEL_EQUIPMENT_KEY_LIST, String.class);
        if (CollUtil.isNotEmpty(keyList)) {
            keyList.forEach(item -> {
                ExcelEquipmentDTO toImport = getExcelEquipmentDTOByName(item);
                String name = toImport.getName();
                List<ExcelEquipmentLabelDTO> labelList = getRedisKey4LabelList(name);
                toImport.setLabelList(labelList);
                List<ExcelParamDTO> redisKey4ParamList = getRedisKey4ParamList(name);
                toImport.setParamList(redisKey4ParamList);
                result.add(toImport);
            });
        }
        return result;
    }

    /**
     * 设置 Excel 设备
     *
     * @param equipmentExcel 设备excel
     */
    @Override
    public void setExcelEquipment(ExcelEquipmentDTO equipmentExcel) {
        setRedis(EXCEL_EQUIPMENT_PREFIX + equipmentExcel.getName(), equipmentExcel);
    }


    /**
     * 获取Excel设备DTOBY名称
     *
     * @param name 名字
     * @return {@link ExcelEquipmentDTO}
     */
    @Override
    public ExcelEquipmentDTO getExcelEquipmentDTOByName(String name) {
        return getRedisByKey(EXCEL_EQUIPMENT_PREFIX + name, ExcelEquipmentDTO.class);
    }

    /**
     * 获取Excel设备DTOBY名称
     *
     * @param name 名字
     * @return {@link ExcelEquipmentDTO}
     */
    @Override
    public ExcelInstrumentDTO getExcelInstrumentDTOByName(String name) {
        return getRedisByKey(EXCEL_INSTRUMENT_PREFIX + name, ExcelInstrumentDTO.class);
    }


    public static final String EXCEL_LABEL_PREFIX = EXCEL_PREFIX + "excelLabel_";



    /**
     * 按路径获取标签
     *
     * @param name 路径
     * @return {@link ExcelEquipmentLabelDTO}
     */
    @Override
    public List<ExcelEquipmentLabelDTO> getRedisKey4LabelList(String name) {
        return listRedisByKey(EXCEL_LABEL_PREFIX + name, ExcelEquipmentLabelDTO.class);
    }

    public static final String EXCEL_PARAM_PREFIX = EXCEL_PREFIX + "excelParam_";

    /**
     * 设置 Redis key4 参数
     *
     * @param key            钥匙
     * @param excelParamList Excel 参数 DTOS
     */
    @Override
    public void setRedisKey4ParamList(String key, List<ExcelParamDTO> excelParamList) {
        pushListRedisByKey(EXCEL_PARAM_PREFIX + key, excelParamList);
    }

    @Override
    public List<ExcelParamDTO> getRedisKey4ParamList(String key) {
        return listRedisByKey(EXCEL_PARAM_PREFIX + key, ExcelParamDTO.class);
    }

    private final String EQUIPMENT_MODEL_PREFIX = EXCEL_PREFIX + "equipmentModel_";
    public static final String EQUIPMENT_MODEL_RELATION_PREFIX = EXCEL_PREFIX + "equipment_model_relation_";
    public static final String MODEL_INFO_PREFIX = EXCEL_PREFIX + "model_info_";

    /**
     * 按设备名称设置所有型号
     *
     * @param mapEquipmentModel 设备型号图
     * @param mapModel          设备型号图
     */
    @Override
    public void setAllModelByEquipmentName(Map<String, String> mapEquipmentModel, Map<String, ModelInfoDTO> mapModel) {
        mapEquipmentModel.forEach((equipmentName, modelName) -> {
            setRedis(EQUIPMENT_MODEL_RELATION_PREFIX + equipmentName, modelName);
        });

        mapModel.forEach((modelName, modelInfoDTO) -> {
            setRedis(MODEL_INFO_PREFIX + modelName, modelInfoDTO);
        });
    }

    private String getModelNameByEquipmentName(String equipmentName) {
        return getRedisByKey(EQUIPMENT_MODEL_RELATION_PREFIX + equipmentName, String.class);
    }

    /**
     * 按模型名称获取模型信息
     *
     * @param modelName 型号名称
     * @return {@link ModelInfoDTO}
     */
    @Override
    public ModelInfoDTO getModelInfoByModelName(String modelName) {
        return getRedisByKey(MODEL_INFO_PREFIX + modelName, ModelInfoDTO.class);
    }

    /**
     * 地图设备名称型号名称
     *
     * @param equipmentNameList 设备名称列表
     * @return {@link Map}<{@link String}, {@link String}>
     */
    @Override
    public Map<String, String> mapEquipmentNameModelName(Collection<String> equipmentNameList) {
        Map<String, String> result = new HashMap<>();
        if (CollUtil.isNotEmpty(equipmentNameList)) {
            equipmentNameList.forEach(equipmentName -> {
                String modelName = getModelNameByEquipmentName(equipmentName);
                result.put(equipmentName, modelName);
            });
        }
        return result;
    }

    /**
     * 按模型名称映射数据参数
     *
     * @param modelNameList 型号名称
     * @return {@link Map}<{@link String}, {@link List}<{@link DataParamTempDTO}>>
     */
    @Override
    public Map<String, List<DataParamTempDTO>> mapDataParamTempByModelNameList(List<String> modelNameList) {
        Map<String, List<DataParamTempDTO>> result = new HashMap<>();
        modelNameList.forEach(modelName -> {
            ModelInfoDTO modelInfoByModelName = getModelInfoByModelName(modelName);
            List<DataParamTempDTO> dataParamTempList = modelInfoByModelName.getDataParamTempList();
            if (CollUtil.isNotEmpty(dataParamTempList)) {
                result.put(modelName, modelInfoByModelName.getDataParamTempList());
            }
        });
        return result;
    }

//    /**
//     * 按设备名称获取型号信息
//     *
//     * @param equipmentName 设备名称
//     * @return {@link ModelInfoDTO}
//     */
//    @Override
//    public ModelInfoDTO getModelInfoByEquipmentName(String equipmentName) {
//        return getModelInfoDTOByName(equipmentName);
//    }

    private ModelInfoDTO getModelInfoDTOByName(String name) {
        return getRedisByKey(EQUIPMENT_MODEL_PREFIX + name, ModelInfoDTO.class);
    }

    /**
     * 按设备名称列出数据参数 temp
     *
     * @param equipmentName 设备名称
     * @return {@link List}<{@link DataParamTempDTO}>
     */
    @Override
    public List<DataParamTempDTO> listDataParamTempByEquipmentName(String equipmentName) {
        ModelInfoDTO modelInfoDTOTwo = getModelInfoDTOByName(equipmentName);
        if (ObjectUtil.isNotEmpty(modelInfoDTOTwo)) {
            return modelInfoDTOTwo.getDataParamTempList();
        }
        return listAllDataParamTempByEquipmentName(equipmentName);
    }

    /**
     * 按参量名称列出数据参数 temp
     *
     * @param paramNameList 设备名称
     * @return
     */
    @Override
    public List<DataParamTempDTO> listDataParamTempByParamName(List<String> paramNameList) {
        List<DataParamTempDTO> list = new ArrayList<>();
        paramNameList.forEach(param->{
            DataParamTempDTO dataParamTempDTO = dataParamTempByDataParamName((param));
            list.add(dataParamTempDTO);
        });
        return list;
    }

    /**
     * 按算法名获取数据参数
     * @param paramNameList
     * @return
     */
    @Override
    public Map<String, AlgorithmTempDTO> listAlgorithmTempByParamName(List<String> paramNameList) {
        Map<String, AlgorithmTempDTO> map = new HashMap<>();
        paramNameList.forEach(param->{
            String jsonStr = redisValueService.get(DATA_PARAM_IMPORT_PREFIX + param);
            AlgorithmDTO algorithm = JSON.parseObject(jsonStr, AlgorithmDTO.class);
            map.put(param,algorithm.getAlgorithm());
        });
        return map;
    }

    /**
     * 按标签名获取数据参数
     * @param
     * @return
     */
    @Override
    public List<LabelTempDTO> listLabelTempByParamName(List<String> paramNameList) {
        List<LabelTempDTO> list = new ArrayList<>();
        paramNameList.forEach(param->{
            LabelTempDTO labelTempDTO = labelTempDTOByDataParamName(param);
            list.add(labelTempDTO);

        });
        return list;
    }

    /**
     * 按报警名获取数据参数
     * @param paramNameList
     * @return
     */
    @Override
    public Map<String,List<AlarmTempDTO>> listAlarmTempByParamName(List<String> paramNameList) {
        Map<String,List<AlarmTempDTO>> map = new HashMap<>();
        paramNameList.forEach(paramName->{
            String str = redisValueService.get(DATA_PARAM_IMPORT_PREFIX + paramName);
            if (StrUtil.isNotEmpty(str)){
                Map<String,Object> alarmTempMap = JSON.parseObject(str, Map.class);
                List<AlarmTempDTO> alarmTempDTOList = (List<AlarmTempDTO>)alarmTempMap.get("alarmList");
                map.put(paramName, alarmTempDTOList);
            }
        });
        return map;
    }

    /**
     * 设置 本次 导入Excel 结果
     *
     * @param result
     */
    @Override
    public void setExcelResult(ExcelResultVO result) {
        Long userId = LocalHolder.getCurrentUser().getUserId();
        ExcelResultVO old = getExcelResult(userId);
        ExcelResultVO newResult = new ExcelResultVO(old, result);
        setRedis(RESULT_MESSAGE + userId, newResult);
    }

    /**
     * 获取 本次 导入Excel 结果
     *
     * @param userId
     * @return {@link ExcelResultVO}
     */
    @Override
    public ExcelResultVO getExcelResult(Long userId) {
        ExcelResultVO redisByKey = getRedisByKey(RESULT_MESSAGE + userId, ExcelResultVO.class);
        if (ObjectUtil.isEmpty(redisByKey)) {
            redisByKey = new ExcelResultVO();
            setRedis(RESULT_MESSAGE + userId, redisByKey);
        }
        return redisByKey;
    }

    public static final String EXCEL_INSTRUMENT_KEY_LIST = EXCEL_PREFIX + "instrumentKeyList_";
    public static final String EXCEL_INSTRUMENT_PREFIX = EXCEL_PREFIX + "excelEquipment_";

    /**
     * 设置所有 Excel 仪器
     *
     * @param instrumentList 仪器清单
     */
    @Override
    public void setAllExcelInstrument(List<ExcelInstrumentDTO> instrumentList) {
        // 获取所有Excel设备名称
        List<String> nameList = instrumentList.stream().map(ExcelInstrumentDTO::getInstrumentName).collect(Collectors.toList());
        pushListRedisByKey(EXCEL_INSTRUMENT_KEY_LIST, nameList);
        // 设置所有Excel设备
        instrumentList.forEach(this::setInstrumentExcel);
    }

    /**
     * 设置仪器 Excel
     *
     * @param excelInstrument Excel 仪器
     */
    @Override
    public void setInstrumentExcel(ExcelInstrumentDTO excelInstrument) {
        setRedis(EXCEL_INSTRUMENT_PREFIX + excelInstrument.getInstrumentName(), excelInstrument);
    }

    /**
     * 列出所有 Excel 仪器
     *
     * @return {@link List}<{@link ExcelInstrumentDTO}>
     */
    @Override
    public List<ExcelInstrumentDTO> listAllExcelInstrument() {
        List<ExcelInstrumentDTO> result = new ArrayList<>();
        List<String> keyList = listRedisByKey(EXCEL_INSTRUMENT_KEY_LIST, String.class);
        if (CollUtil.isNotEmpty(keyList)) {
            assert keyList != null;
            keyList.forEach(item -> {
                ExcelInstrumentDTO toImport = getExcelInstrumentDTOByName(item);
                result.add(toImport);
            });
        }
        return result;
    }

    /**
     * SET Redis KEY4 仪器市场调查数据一览
     *
     * @param instrumentName       仪器名称
     * @param instrumentReportList 仪器 市场调查报告一览
     */
    @Override
    public void setRedisKey4InstrumentReportList(String instrumentName,
                                                 List<ExcelInstrumentReportDTO> instrumentReportList) {
        ExcelInstrumentDTO excelInstrument = getExcelInstrumentDTOByName(instrumentName);
        excelInstrument.setInstrumentReportList(instrumentReportList);
        setInstrumentExcel(excelInstrument);
    }

    public static final String RESULT_MESSAGE = EXCEL_PREFIX + "resultMessage_";

    private void setCodeRuleMessage(String logRecordName, ExcelCodeRuleEnum ruleEnum) {
        ExcelResultVO newResult = new ExcelResultVO();
        newResult.setCodeRuleMessage(logRecordName, ruleEnum);
        setExcelResult(newResult);
    }

    private <T> List<T> listRedisByKey(String key, Class<T> clazz) {
        String strList = redisValueService.get(key);
        if ("".equals(strList)) {
            return null;
        }
        return JSON.parseArray(strList, clazz);
    }

    private void pushListRedisByKey(String key, List<?> toSaveList) {
        if (CollUtil.isEmpty(toSaveList)) {
            toSaveList = CollUtil.newArrayList();
        }
        redisValueService.set(key, JSON.toJSONString(toSaveList), 1L, TimeUnit.HOURS);
    }


    private Map<String, List<AlarmTempDTO>> buildAlarmExcelDTOList(List<ExcelAlarmVO> alarmExcelList) {
        Map<String, String> dictAlarmTypeMap = mapDict(DICT_ALARM_TYPE);
        Map<String, String> dictAlarmLevelMap = mapDict(DICT_ALARM_LEVEL);
        Map<String, List<AlarmTempDTO>> result = new HashMap<>();
        Map<String, List<ExcelAlarmVO>> map = alarmExcelList.stream()
                .collect(Collectors.groupingBy(ExcelAlarmVO::getDataParamName));

        map.forEach((key, value) -> {
            List<AlarmTempDTO> tempList = new ArrayList<>();
            value.forEach(vo -> {
                AlarmTempDTO alarmExcelDTO = BeanUtils.copyToObject(vo, AlarmTempDTO.class);
                String type = dictAlarmTypeMap.get(vo.getAlarmType());
                String level = dictAlarmLevelMap.get(vo.getAlarmClass());
                if (StrUtil.isNotBlank(type) && StrUtil.isNotBlank(level)) {
                    alarmExcelDTO.setAlarmType(type);
                    alarmExcelDTO.setAlarmClass(level);
                    tempList.add(alarmExcelDTO);
                }
            });
            result.put(key, tempList);
        });
        return result;
    }




    private AlgorithmTempDTO buildAlgorithmTempDTO(DataAlgorithmScriptAndFormulaDTO algorithmDTO) {
        AlgorithmTempDTO algorithmTempDTO = new AlgorithmTempDTO();
        DataAlgorithmDTO algorithm = algorithmDTO.getDataAlgorithmDTO();
        if (ObjectUtil.isNotEmpty(algorithm)) {
            algorithmTempDTO.setAlgorithmName(algorithm.getName());
            algorithmTempDTO.setAlgorithmId(algorithm.getId());
            algorithmTempDTO.setAlgorithmConfigurationScheme(algorithm.getConfigurationScheme());
            algorithmTempDTO.setAlgorithmDescription(algorithm.getDescription());
            algorithmTempDTO.setAlgorithmAccuracyDigit(algorithm.getAccuracyDigit());
        }
        String scheme = algorithm.getConfigurationScheme();
        if (DataAlgorithmTypeEnum.SCRIPT.getType().equals(scheme)) {
            DataAlgorithmScriptConfigDTO script = algorithmDTO.getDataAlgorithmScriptConfigDTO();
            algorithmTempDTO.setScriptPath(script.getScriptPath());
            algorithmTempDTO.setRequestType(script.getRequestType());
            List<DataAlgorithmParamConfigDTO> paramConfigDTOList = script.getParamConfigDTOList();
            algorithmTempDTO.setParamTempList(buildDataParamList(paramConfigDTOList));
        } else if (DataAlgorithmTypeEnum.FORMULA.getType().equals(scheme)) {
            DataAlgorithmFormulaConfigDTO formula = algorithmDTO.getDataAlgorithmFormulaConfigDTO();
            algorithmTempDTO.setAlgorithmFormula(formula.getFormula());
            List<DataAlgorithmParamConfigDTO> paramConfigDTOList = formula.getParamConfigDTOList();
            algorithmTempDTO.setParamTempList(buildDataParamList(paramConfigDTOList));
        }
        return algorithmTempDTO;
    }

    private List<ParamTempDTO> buildDataParamList(List<DataAlgorithmParamConfigDTO> tempList) {
        if (CollUtil.isNotEmpty(tempList)) {
            return tempList.stream().map(temp -> {
                ParamTempDTO paramTempDTO = new ParamTempDTO();
                paramTempDTO.setParamId(temp.getId());
                paramTempDTO.setParamSign(temp.getMark());
                paramTempDTO.setParamDesc(temp.getDescription());
                paramTempDTO.setParamType(temp.getMappedType());
                paramTempDTO.setVariableValue(temp.getGlobalVariableValue());
                paramTempDTO.setVariableDeclaration(temp.getGlobalVariableDescription());
                return paramTempDTO;
            }).collect(Collectors.toList());
        }
        return new ArrayList<>();
    }

    private <T> T getRedisByKey(String key, Class<T> t) {
        String string = getRedisByKey(key);
        if (StrUtil.isBlank(string) || "null".equals(string)) {
            return null;
        } else {
            return JSON.parseObject(string, t);
        }
    }

    private String getRedisByKey(String key) {
        return redisValueService.get(key);
    }

    private void setRedis(String key, Object value) {
        if (ObjectUtil.isEmpty(value)) {
            return;
        }
        redisValueService.set(key, JSON.toJSONString(value), 1L, TimeUnit.HOURS);
    }

    private void setRedisByKey(String key, String value) {
        if (StrUtil.isBlank(value)) {
            return;
        }
        redisValueService.set(key, value, 1L, TimeUnit.HOURS);
    }

    private List<DataParamTempVO> buildDataParamListPref(List<ExcelDataParamVO> excelDataParamVOList,
                                                         DataParamImportEnum relationType) {
        List<DataParamTempVO> result = new ArrayList<>();
        excelDataParamVOList.forEach(vo -> {
            DataParamTempVO dataParam = BeanUtils.copyToObject(vo, DataParamTempVO.class);
            // 设备模型名称/设备名称
            String relationName = vo.getRelationName();
            if (StrUtil.isBlank(relationName)) {
                // todo 是否需要处理
                return;
            }
            dataParam.setEquipmentName(relationName);
            setByEnum(vo, dataParam);
            result.add(dataParam);
        });
        return result;
    }

    private void setByEnum(ExcelDataParamVO vo, DataParamTempVO dataParam) {
        Integer codeByName = DataParamSourceEnum.getCodeByName(vo.getSourceStr().trim());
        if (ObjectUtil.isNotEmpty(codeByName)) {
            dataParam.setSource(codeByName);
        }

        DataParamTypeEnum type = DataParamTypeEnum.getByName(vo.getDataTypeStr().trim());
        if (ObjectUtil.isNotEmpty(type)) {
            dataParam.setDataType(type.getType());
        }
        String chartStr = vo.getChartStr();
        if (StrUtil.isNotBlank(chartStr)) {
            DataParamChartEnum chartEnum = DataParamChartEnum.getByName(vo.getChartStr().trim());
            if (ObjectUtil.isNotEmpty(chartEnum)) {
                dataParam.setChart(chartEnum.getChart());
            }
        }
        Optional.ofNullable(vo.getPowerCheckDisplayStr())
                .ifPresent(str -> dataParam.setPowerCheckDisplay("是".equals(str.trim())));
        dataParam.setStatus(0);
    }
}
